<template>
    <div class="main">
        <h1>倾听数据的源类型</h1>
        <p> watch 的第一个参数可以是不同形式的“数据源”：它可以是一个 ref(包括计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组：</p><br>
        <p>watchEffect() 允许我们自动跟踪回调的响应式依赖</p><br>
        inputVal: <input v-model="inputVal" type="text"><br><br>
        <div>
            <label for="">num1: </label>
            <input type="number" v-model="num1">
            <br>
            <br>
            <label for="">num2: </label>
            <input type="number" v-model="num2">
            <br>
            <br>
            <p>求和：{{ getSum }}</p>
        </div>
        <br>
        <hr><br>
        <div>
            <label for="">user.name: </label>
            <input type="text" v-model="user.name">
            <br>
            <br>
            <label for="">user.sex: </label>
            <input type="text" v-model="user.sex">
            <br>
            <br>
            <label for="">user.love.basketball: </label>
            <input type="text" v-model="user.love.basketball">
        </div>
    </div>
</template>

<script lang="ts">
export default {
    name: 'diyDemo315'
}
</script>

<script setup lang='ts'>
import { computed, reactive, ref, watch, watchEffect } from 'vue';

// 数据
const inputVal = ref('默认值')
const num1 = ref(0)
const num2 = ref(0)
const user = reactive({
    name: 'Cui梦娇',
    sex: '女',
    love: {
        basketball: '篮球'
    }
})

// 计算属性
const getSum = computed(() => {
    return num1.value + num2.value
})

// 监听ref
watch(inputVal, (newVal, oldVal) => {
    console.log('inputVal-ref-newVal:', newVal, 'inputVal-ref-oldVal:', oldVal);

})

watchEffect(() => {
    console.log(inputVal.value, 'watchEffect-inputVal');

})

// 监听计算属性
watch(getSum, (newVal, oldVal) => {
    console.log('getSum-newVal:', newVal, 'getSum-oldVal:', oldVal);
})

watchEffect(() => {
    console.log(getSum.value, 'watchEffect-getSum');

})


// 监听 inputVal getter 函数
watch(() => inputVal.value, (newVal, oldVal) => {
    console.log('inputVal-getter-newVal:', newVal, 'inputVal-getter-oldVal:', oldVal);
})

watchEffect(() => {
    console.log((() => inputVal.value)(), 'watchEffect-getter-inputVal');

})

// 监听 getSum getter 函数
watch(() => num1.value * num2.value, (newVal, oldVal) => {
    console.log('getSum-getter-newVal:', newVal, 'getSum-getter-oldVal:', oldVal);

})

watchEffect(() => {
    console.log((() => num1.value * num2.value)(), 'watchEffect-getter-getSum:');
})

// 监听多个数据源组成的数组
watch([inputVal, () => num1.value + num2.value, () => inputVal.value, () => num1.value * num2.value], (arr) => {
    console.log('arr:', arr);

})

// 但是对于有多个依赖项的侦听器来说，使用 watchEffect() 可以消除手动维护依赖列表的负担
watchEffect(() => {
    const [ipt, cheng, ival, sum] = [
        inputVal.value,
        (() => num1.value * num2.value)(),
        (() => inputVal.value)(),
        (() => num1.value + num2.value)()
    ]
    console.log(ipt, cheng, ival, sum, 'watchEffect-arr');

    // const arr = [
    //     inputVal.value,
    //     (() => num1.value * num2.value)(),
    //     (() => inputVal.value)(),
    //     (() => num1.value + num2.value)()
    // ]
    // console.log(arr, 'watchEffect-arr');

})


// 注意，你不能直接监听‘响应式对象’的属性值，例如以下错误示例：
// watch(user.name, (newVal, oldVal) => {

// })
// 可以使用 getter 函数 侦听‘响应式对象’的属性值
watch(() => user.name, (newVal, oldVal) => {
    console.log('user.name-getter-newVal:', newVal, 'user.name-getter-oldVal:', oldVal);
})

// 监听整个对象
// 直接给 watch() 传入一个响应式对象，会‘隐式的创建一个深层侦听器’，该回调函数在所有嵌套的变更时都会被触发：
watch(user, (newVal, oldVal) => {
    console.log('user-newVal:', newVal, 'user-oldVal:', oldVal);
})

// // 显示地加上 deep 选项，强制转成深层侦听器
watch(user, (newVal, oldVal) => {
    console.log('user-deep-newVal:', newVal, 'user-deep-oldVal:', oldVal);
}, { deep: true })

// 显示地关闭 deep 选项，强制转成浅层侦听器
// 浅层监听，深层的属性值被改变时不会被监听到，但值依然会被响应式改变
watch(user, (newVal, oldVal) => {
    console.log('user-shallow-newVal:', newVal, 'user-shallow-oldVal:', oldVal);
}, { deep: false })

// 即时回调的侦听器
// 在监听数据改变之前，先触发一次
watch(inputVal, (newVal, oldVal) => {
    console.log('inputVal-immediate-newVal:', newVal, 'inputVal-immediate-oldVal:', oldVal);

}, {
    // immediate: true
}) // 先触发一次

// 一次性监听器
// 只会监听一次
watch(inputVal, (newVal, oldVal) => {
    console.log('inputVal-once-newVal:', newVal, 'inputVal-once-oldVal:', oldVal);

}, {
    // immediate: true,
    // once和immediate共同使用请注意，once会被immediate触发的一次性监听消费掉，所以它们两个一起使用没有意义。
    once: true
})

</script>

<style lang="scss">
.main {
    margin: 20px;
}
</style>